#ifndef GENERATOR_H
#define GENERATOR_H


#include <tuple>
#include <any>
#include <memory>
#include <vector>
#include "awaiters.h"

#include "coroutine.h"
#include "ccoroutine_core_global.h"

namespace CCoroutine{

//用于作为生成器的协程
template<typename T,typename ...Args>
class Generator:public ArgedPromise<Args...>
{
public:
    class Controller:public ControllerBase{
    public:
        Controller(){

        }

        Controller(Controller&& o):ControllerBase(std::move(o)){

        }

        Controller& operator =(Controller&& o){
            ControllerBase::operator =(std::move(o));
            return *this;
        }

        ~Controller(){
            if(base)
            {
                delete base;
            }

        }

        class Iterator{
        public:
            Iterator(Generator* generator):generator(generator){

            }

            bool operator ==(const Iterator& o){
                return generator == o.generator;
            }

            bool operator !=(const Iterator& o){
                return generator != o.generator;
            }

            T operator*(){
                if(!generator) return {};
                return generator->yield_value;
            }

            T* operator->(){
                if(!generator) return nullptr;
                return &generator->yield_value;
            }

            Iterator& operator++(){
                if(!generator) return *this;
                generator->resume();
                if(generator->finished)
                {
                    generator = nullptr;
                }
                return *this;
            }

        private:
            Generator* generator = nullptr;
        };

        Iterator begin(){
            base->resume();
            if(base->status() == PromiseBase::Finished)
            {
                return {nullptr};
            }
            return {dynamic_cast<Generator*>(base)};
        }

        Iterator end(){
            return {nullptr};
        }

    };

    Generator(){

    }

    SuspendAlways* initial_suspend(){
        return new SuspendAlways{};
    }

    SuspendAlways* final_suspend(){
        finished = true;
        return new SuspendAlways{};
    }

    SuspendAlways* on_yield(const T& t){
        yield_value = t;
        return new SuspendAlways{};
    }

private:
    T yield_value;
    bool finished = false;
    friend class Controller;
    friend class Controller::Iterator;
};
}
#endif
